package main

import (
	"fmt"
	"reflect"
	"errors"
)

type Person struct {
	Name string
	Age int
	Address string
}

type Pet struct {
	Color string
	Name string
	Age int
}

func SetProp(target interface{}, kv map[string]interface{}) error {
	if target == nil {
		return errors.New("target can not be nil")
	}

	pTargetType:=reflect.TypeOf(target)
	if pTargetType.Kind() != reflect.Ptr {
		return errors.New("target must be a pointer")
	}

	targetType:=pTargetType.Elem()
	if targetType.Kind() != reflect.Struct {
		return errors.New("target must be a pointer of struct")
	}

	for name, prop := range kv {
		field,fieldExist:=targetType.FieldByName(name)
		if !fieldExist { continue }

		targetValue:=reflect.ValueOf(target).Elem()
		targetField:=targetValue.FieldByName(name)
		fieldType:=field.Type

		propType:=reflect.TypeOf(prop)
		if fieldType != propType {
			return errors.New("target prop " + name + "'s type is different from assign value")
		}

		targetField.Set(reflect.ValueOf(prop))
	}

	return nil
}

func main() {
	per:=&Person{}
	pet:=&Pet{}

	var props map[string]interface{} = map[string]interface{}{
		"Name": "damao",
		"Age": 20,
	}

	if err:=SetProp(per, props); err!=nil {
		fmt.Println(err)
	}

	if err:=SetProp(pet, props); err!=nil {
		fmt.Println(err)
	}

	fmt.Println(per)
	fmt.Println(pet)
}
